package application;

import java.util.HashMap;
import java.util.Map;

/**
 * Implements the functionality of the third NAUI table aka the Repetitive Dive
 * Timetable. This table is only accessed when user selects for multiple dives.
 * 
 * Multiple Dives:
 * 
 * <> Input: (fr: Table 2) char groupLetter (fr: User) int depth and int time
 * 
 * <> Output: int depth and int time - both used by Table 1
 * 
 * Other Assumptions:
 * 
 * <> Table 3 assumes that GUI will prevent impossible inputs
 *
 */
public class ThirdNAUITable implements NAUITable {
	private char letterGroup;
	private int depth, time;
	private Map<Character, Map<Integer, Integer[]>> table;

	/**
	 * Creates Table 3 and sets initial values.
	 */
	public ThirdNAUITable() {
		this.letterGroup = DivePlan.INITIAL_GROUP;
		this.depth = 0;
		this.time = 0;

		table = new HashMap<Character, Map<Integer, Integer[]>>();
		this.createTable();
	}

	/**
	 * Returns current table
	 * 
	 * @return
	 */
	public Map<Character, Map<Integer, Integer[]>> getTable() {
		return table;
	}

	/**
	 * Retrieves currently set letterGroup.
	 * 
	 * If letterGroup is '?', the inputs for letterGroup, depth, and/or time
	 * have NEVER been given.
	 * 
	 * @return letterGroup given
	 */
	public char getLetterGroup() {
		return letterGroup;
	}

	/**
	 * Retrieves currently set depth.
	 * 
	 * If depth is 0, the inputs for letterGroup, depth, and/or time have NEVER
	 * been given.
	 * 
	 * @return depth calculated
	 */
	public int getDepth() {
		return depth;
	}

	/**
	 * Retrieves currently set time.
	 * 
	 * If depth is 0, the inputs for letterGroup, depth, and/or time have NEVER
	 * been given.
	 * 
	 * @return time calculated
	 */
	public int getTime() {
		return time;
	}

	/**
	 * Changes the current letterGroup. Calculates and sets the new time based
	 * on change.
	 * 
	 * @param letterGroup
	 *            from Table 2
	 */
	public void setLetterGroup(char letterGroup) {
		this.setLetterGroupAndDepthAndTime(letterGroup, depth, time);
	}

	/**
	 * Changes the current depth. Calculates and sets the new time based on
	 * change.
	 * 
	 * @param depth
	 *            from Table 2
	 */
	public void setDepth(char depth) {
		this.setLetterGroupAndDepthAndTime(letterGroup, depth, time);
	}

	/**
	 * Changes the current time. Calculates and sets the new time based on
	 * change.
	 * 
	 * @param time
	 *            from Table 2
	 */
	public void setTime(char time) {
		this.setLetterGroupAndDepthAndTime(letterGroup, depth, time);
	}

	/**
	 * Changes the current letterGroup, depth, and time. Calculates and sets the
	 * new time based on change.
	 * 
	 * @param letterGroup
	 *            from Table 2
	 * @param depth
	 *            from Table 2
	 * @param time
	 *            from Table 2
	 */
	public void setLetterGroupAndDepthAndTime(char letterGroup, int depth,
			int time) {
		this.letterGroup = letterGroup;
		this.depth = depth;
		this.time = time;

		this.calcOutput();
	}

	/**
	 * Calculates and sets time based on current values for letterGroup, depth,
	 * and time inputs.
	 */
	private void calcOutput() {
		Integer[] range = table.get(this.letterGroup).get(this.depth);
		this.time = this.time + range[0];
	}

	/**
	 * Creates Table 3.
	 */
	@SuppressWarnings("serial")
	private void createTable() {
		Map<Integer, Integer[]> A = new HashMap<Integer, Integer[]>() {
			{
				put(40, new Integer[] { 7, 123 });
				put(50, new Integer[] { 6, 74 });
				put(60, new Integer[] { 5, 50 });
				put(70, new Integer[] { 4, 41 });
				put(80, new Integer[] { 4, 31 });
				put(90, new Integer[] { 3, 22 });
				put(100, new Integer[] { 3, 19 });
				put(110, new Integer[] { 3, 12 });
				put(120, new Integer[] { 3, 9 });
				put(130, new Integer[] { 3, 5 });
			}
		};
		Map<Integer, Integer[]> B = new HashMap<Integer, Integer[]>() {
			{
				put(40, new Integer[] { 17, 113 });
				put(50, new Integer[] { 13, 67 });
				put(60, new Integer[] { 11, 44 });
				put(70, new Integer[] { 9, 36 });
				put(80, new Integer[] { 8, 27 });
				put(90, new Integer[] { 7, 18 });
				put(100, new Integer[] { 7, 15 });
				put(110, new Integer[] { 6, 9 });
				put(120, new Integer[] { 6, 6 });
				put(130, null);
			}
		};
		Map<Integer, Integer[]> C = new HashMap<Integer, Integer[]>() {
			{
				put(40, new Integer[] { 25, 105 });
				put(50, new Integer[] { 21, 59 });
				put(60, new Integer[] { 17, 38 });
				put(70, new Integer[] { 15, 30 });
				put(80, new Integer[] { 13, 22 });
				put(90, new Integer[] { 11, 14 });
				put(100, new Integer[] { 10, 12 });
				put(110, new Integer[] { 10, 5 });
				put(120, null);
				put(130, null);
			}
		};
		Map<Integer, Integer[]> D = new HashMap<Integer, Integer[]>() {
			{
				put(40, new Integer[] { 37, 93 });
				put(50, new Integer[] { 29, 51 });
				put(60, new Integer[] { 24, 31 });
				put(70, new Integer[] { 20, 25 });
				put(80, new Integer[] { 18, 17 });
				put(90, new Integer[] { 16, 9 });
				put(100, new Integer[] { 14, 8 });
				put(110, null);
				put(120, null);
				put(130, null);
			}
		};
		Map<Integer, Integer[]> E = new HashMap<Integer, Integer[]>() {
			{
				put(40, new Integer[] { 49, 81 });
				put(50, new Integer[] { 38, 42 });
				put(60, new Integer[] { 30, 25 });
				put(70, new Integer[] { 26, 19 });
				put(80, new Integer[] { 23, 12 });
				put(90, new Integer[] { 20, 5 });
				put(100, new Integer[] { 18, 4 });
				put(110, null);
				put(120, null);
				put(130, null);
			}
		};
		Map<Integer, Integer[]> F = new HashMap<Integer, Integer[]>() {
			{
				put(40, new Integer[] { 61, 69 });
				put(50, new Integer[] { 47, 33 });
				put(60, new Integer[] { 36, 19 });
				put(70, new Integer[] { 31, 14 });
				put(80, new Integer[] { 28, 7 });
				put(90, null);
				put(100, null);
				put(110, null);
				put(120, null);
				put(130, null);
			}
		};
		Map<Integer, Integer[]> G = new HashMap<Integer, Integer[]>() {
			{
				put(40, new Integer[] { 73, 57 });
				put(50, new Integer[] { 56, 24 });
				put(60, new Integer[] { 44, 11 });
				put(70, new Integer[] { 37, 8 });
				put(80, null);
				put(90, null);
				put(100, null);
				put(110, null);
				put(120, null);
				put(130, null);
			}
		};
		Map<Integer, Integer[]> H = new HashMap<Integer, Integer[]>() {
			{
				put(40, new Integer[] { 87, 43 });
				put(50, new Integer[] { 66, 14 });
				put(60, null);
				put(70, null);
				put(80, null);
				put(90, null);
				put(100, null);
				put(110, null);
				put(120, null);
				put(130, null);
			}
		};
		Map<Integer, Integer[]> I = new HashMap<Integer, Integer[]>() {
			{
				put(40, new Integer[] { 101, 29 });
				put(50, new Integer[] { 76, 4 });
				put(60, null);
				put(70, null);
				put(80, null);
				put(90, null);
				put(100, null);
				put(110, null);
				put(120, null);
				put(130, null);
			}
		};
		Map<Integer, Integer[]> J = new HashMap<Integer, Integer[]>() {
			{
				put(40, new Integer[] { 116, 14 });
				put(50, null);
				put(60, null);
				put(70, null);
				put(80, null);
				put(90, null);
				put(100, null);
				put(110, null);
				put(120, null);
				put(130, null);
			}
		};
		Map<Integer, Integer[]> K = new HashMap<Integer, Integer[]>() {
			{
				put(40, null);
				put(50, null);
				put(60, null);
				put(70, null);
				put(80, null);
				put(90, null);
				put(100, null);
				put(110, null);
				put(120, null);
				put(130, null);
			}
		};
		Map<Integer, Integer[]> L = new HashMap<Integer, Integer[]>() {
			{
				put(40, null);
				put(50, null);
				put(60, null);
				put(70, null);
				put(80, null);
				put(90, null);
				put(100, null);
				put(110, null);
				put(120, null);
				put(130, null);
			}
		};
		table.put('A', A);
		table.put('B', B);
		table.put('C', C);
		table.put('D', D);
		table.put('E', E);
		table.put('F', F);
		table.put('G', G);
		table.put('H', H);
		table.put('I', I);
		table.put('J', J);
		table.put('K', K);
		table.put('L', L);
	}
}
